iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 6
0
Software Development

從生活中認識Design Pattern系列 第 6

[Day06] 介面隔離原則 | Interface Segregation Principle

  • 分享至 

  • xImage
  •  

本文同步分享於個人blog

第四個原則,不禁讓我想起前輩說,身為一個工程師,多元工作內容也是很合理的一件事。讓我們看看什麼是介面隔離原則吧。

  • 定義


Clients should not be forced to depend on methods that they do not use.

翻譯年糕:客戶不應該被強迫依賴他們不使用的方法。

回想當我們在公司工作時,除了寫程式、抓bug,資深一點的或許還要做簡報...等等多元的工作內容,我們用程式來呈現我們的情況:

interface Skill{
    public void coding();
    public void debug();
    public void prepareSlides();
}
class SeniorEngineer implements Skill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("做老闆的報告!!");
    };
}


public class Company {
    public static void main(String args[]) {
      SeniorEngineer se = new SeniorEngineer();
      System.out.println("SeniorEngineer 上班");
      se.coding();
      se.debug();
      se.debug();
    }
}

output

SeniorEngineer 上班
當碼農!!
找蟲!!
做老闆的報告!!

這段程式呈現了身為一個Senior Engineer,上班需要做的工作!!但這樣存在著什麼問題呢?

假如公司今天招募了一個Junior Engineer,如下:

interface Skill{
    public void coding();
    public void debug();
    public void prepareSlides();
}
class JuniorEngineer implements Skill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("我不會做報告!!");
    };
}
public class Company {
    public static void main(String args[]) {
      JuniorEngineer je = new JuniorEngineer();
      System.out.println("SeniorEngineer 上班");
      je.coding();
      je.debug();
      je.prepareSlides();
    }
}

output

JuniorEngineer 上班
當碼農!!
找蟲!!
我不會做報告!!

剛報到的Junior Engineer,他會coding,也會debug,可是他並不會做簡報。但他一定要實作Skill介面的方法,那該怎麼辦?剛剛定義有提到,客戶不應該被強迫依賴他們不使用的方法。顯然這個整體規劃的需要做一些更改。可能是公司招聘需求是要會做簡報的工程師,不然就是公司要把這個技能條件拆分出來。

  • 實作Interface segregation principle


為了讓公司的員工分工明確一點,我們把Skill分成TechSkill以及OtherSkill

interface TechSkill{
    public void coding();
    public void debug();
}

interface OtherSkill{
    public void prepareSlides();
}

class SeniorEngineer implements TechSkill, OtherSkill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
    public void prepareSlides(){
        System.out.println("做老闆的報告!!");
    };
}

class JuniorEngineer implements TechSkill{
    public void coding(){
        System.out.println("當碼農!!");
    };
    public void debug(){
        System.out.println("找蟲!!");
    };
}
public class Company {
    public static void main(String args[]) {
      SeniorEngineer se = new SeniorEngineer();
      System.out.println("SeniorEngineer work");
      se.coding();
      se.debug();
      se.prepareSlides();
      
      JuniorEngineer je = new JuniorEngineer();
      System.out.println("JuniorEngineer work");
      je.coding();
      je.debug();
    }
}

output

SeniorEngineer work
當碼農!!
找蟲!!
做老闆的報告!!
JuniorEngineer work
當碼農!!
找蟲!!

重新設計後,Senior和Junior所應該要會的技能已經被分類,Junior不在需要實作他不會的技能,他只需要專心的做她份內的事。未來若OtherSkill內需要增加其他工作時也不會影響JuniorEngineer的工作!!!

我們來看看UML了解一下兩者結構上的差異:

ISP1

上圖表示為我們原本的設計,如果把所有的技能都放在同一個interface的話,這樣被迫class都要實作每一個技能,但並不是每個class都須要實作每個技能。所以我們把整體結構改成下圖:

ISP2

可以發現,遵守ISP原則後,JuniorEngineer不再強迫要實作prepareSlides的function,他只需要做好TechSkill內的function即可。

現在我們理解在一個interface內不需要將所有的功能都包在其中,應該挑出對應的需求放入,減低interface肥大的問題,也不需要煩惱class實作不需要的function問題,減少class間的耦合性。

SRP與ISP的差異

看完這SRP與IRP兩篇的人可能會覺得,SRP跟IRP不都是拆分interface嗎?那有什麼不同?

SRP的目的在於一個模組只能有承擔一個責任。
ISP的目的在於不強迫實作的類別實作不需要的function。

我們可以用不同的角度去看這件事。

SRP注重的是設計層面,如何劃分功能的歸類,讓程式方便維護及擴充。
ISP則是注重在客戶端層面,認為只需要呈現客戶端所需要的功能即可。
  • 小結


ISP的目標:

1. 不要讓interface包過多的功能。
2. 不應該強迫實作沒有用到的方法。
3. 實現class間的低耦合。
  • 範例程式碼


範例1:SeniorEngineer
範例2:JuniorEngineer
範例3:實作ISP

  • References


設計模式五大基本原則 SOLID
介面隔離原則


上一篇
[Day05] 里氏替換原則 | Liskov Substitution Principle
下一篇
[Day07] 依賴反轉原則 | Dependency Inversion Principle
系列文
從生活中認識Design Pattern30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言